#ifndef STYLEEXCEPTION_H
#define STYLEEXCEPTION_H

#include <QList>
#include <QColor>
#include <QString>
#include <QVariant>
#include <QException>
#include <QByteArray>
#include <QScopedPointer>
#include <QRegularExpression>

#include <functional>
#include <exception>

// 自定义样式异常类
class StyleException : public QException
{
private:
    QByteArray error;

public:
    StyleException(QString errorMessage) : error(errorMessage.toUtf8())
    {
    }

//    virtual const char *what() const override // error
//    virtual const char *what() const throw()
    virtual const char *what() const noexcept override // c++11 之后 throw() 被 noexcept 代替
    {
        return error.constData();
    }
};

// 可自行封装添加
enum class CapturingContent : int
{
    border_radius = 0,     // 返回边框圆角半径
    background_Qcolor = 1, // 返回背景颜色
    color = 2              // 返回 color 颜色，一般为字体颜色
};

class StyleSheetParser
{
public:
    StyleSheetParser(QString style) : styleSheet(style) {}

private:
    QString styleSheet;

    // 可自行封装添加
    static QRegularExpression BorderRadius;
    static QRegularExpression bkRGBA;
    static QRegularExpression bkRGB;
    static QRegularExpression colorRGBA;
    static QRegularExpression colorRGB;

    // 获取圆角半径
    std::function<int()> border_radius{
        [&]
        {
            if (BorderRadius.match(styleSheet).hasMatch())
                return BorderRadius.match(styleSheet).captured(1).toInt();
            else // 无匹配结果，抛出StyleException异常(父类是QException)可多态接收
                throw StyleException{QString{"No matching target found"}};
        }};

    // 获取 QColor 颜色，根据正则的不同,获取不同属性的颜色，如果没有透明度则透明度为默认值255
    std::function<QColor(QRegularExpression, QRegularExpression)> Qcolor{
        [&](QRegularExpression RGBAreg, QRegularExpression RGBreg)
        {
            if (RGBAreg.match(styleSheet).hasMatch())
            {
                int R{RGBAreg.match(styleSheet).captured(1).toInt()};
                int G{RGBAreg.match(styleSheet).captured(2).toInt()};
                int B{RGBAreg.match(styleSheet).captured(3).toInt()};
                int A{RGBAreg.match(styleSheet).captured(4).toInt()};
                return QColor(R, G, B, A);
            }

            else if (RGBreg.match(styleSheet).hasMatch())
            {
                int R{RGBreg.match(styleSheet).captured(1).toInt()};
                int G{RGBreg.match(styleSheet).captured(2).toInt()};
                int B{RGBreg.match(styleSheet).captured(3).toInt()};
                return QColor(R, G, B, 255);
            }
            else
                throw StyleException{QString("No matching target found")};
        }};

public:
    // 转换函数，将 QColor 转换成 QSring，形如：rgba(0,0,0,0)
    QString QColorToQString(const QColor &color)
    {
        return QString("rgba(" + QString::number(color.red()) + "," +
                       QString::number(color.green()) + "," +
                       QString::number(color.blue()) + "," +
                       QString::number(color.alpha()) + ")");
    }

    // 写好的正则直接提供使用 // 可自行封装添加
    QVariant SpecificStyles(CapturingContent CapturingContent)
    {
        switch (CapturingContent)
        {
        case CapturingContent::border_radius:
            return QVariant{border_radius()};
            // 圆角半径 int
            break;
        case CapturingContent::background_Qcolor:
            return QVariant{Qcolor(bkRGBA, bkRGB)};
            // 背景颜色 QColor
        case CapturingContent::color:
            return QVariant{Qcolor(colorRGBA, colorRGB)};
            // （一般为）字体颜色 QColor
            break;
        default:
            return QVariant();
            break;
        }
    }

    // 重载1 // 也可自行传入正则表达式进行匹配,参数:正则表达式,捕获数量，返回:存储捕获结果的QList
    QList<QString> SpecificStyles(const QString &regex_str, const int catchesNum)
    {
        QScopedPointer<QRegularExpression> reg{new QRegularExpression{regex_str}};
        QList<QString> result;
        if (reg->match(styleSheet).hasMatch())
        {
            for (int i = 0; i < catchesNum; i++)
                result.push_back(reg->match(styleSheet).captured(i));
        }
        else
            throw StyleException{QString("No matching target found")};
        return result;
    }

    // 重载2 // 传入正则对象，其余不变
    QList<QString> SpecificStyles(const QRegularExpression &regex, const int catchesNum)
    {
        QList<QString> result;
        if (regex.match(styleSheet).hasMatch())
        {
            for (int i = 0; i < catchesNum; i++)
                result.push_back(regex.match(styleSheet).captured(i));
        }
        else
            throw StyleException{QString("No matching target found")};
        return result;
    }
};

QRegularExpression StyleSheetParser::BorderRadius{"border-radius\\s*:\\s*(\\d+)\\s*px"};
QRegularExpression StyleSheetParser::bkRGBA{"background-color\\s*:\\s*rgba[(]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)"};
QRegularExpression StyleSheetParser::bkRGB{"background-color\\s*:\\s*rgb[(]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)"};
QRegularExpression StyleSheetParser::colorRGBA{"(?<!-)(?<=^|;)\\s*color\\s*:\\srgba\\s*[(](\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[)]"};
QRegularExpression StyleSheetParser::colorRGB{"(?<!-)(?<=^|;)\\s*color\\s*:\\srgb\\s*[(](\\d+)\\s*[,]\\s*(\\d+)\\s*[,]\\s*(\\d+)\\s*[)]"};

#endif // STYLEEXCEPTION_H
